package cn.cs.message.tempstorage.disk;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.cs.message.Message;

public class DiskWriter 
{
	private static final Logger logger=LoggerFactory.getLogger(DiskWriter.class);
	private static final int CHUNK_SIZE = 4096;
	private static final long MAX_FILE_LENGTH=200000000l;
	
	private String path;
	private File file;
	private List<File> files=new ArrayList<File>();
	
	private long position=0;
	private FileChannel channel;
	private MappedByteBuffer buffer;
	private RandomAccessFile randomAccessFile;
	
	public DiskWriter(String path)
	{
		this.path=path;
		changeOtherFile();
	}
	
	public boolean write(Message msg)
	{
		MsgEncoder encoder=new MsgEncoder(msg);
		int length=encoder.size();
		buffer = getBuffer(length);
		if(buffer==null)
			return false;
		
		encoder.encode(buffer);
		position+=length;
		if(position>MAX_FILE_LENGTH)
			changeOtherFile();
		return true;
	}
	
	/**获得max{length,N}大小的内存映射*/
	private MappedByteBuffer getBuffer(long length) 
	{
		length=length>CHUNK_SIZE?length:CHUNK_SIZE;
		
		try {
			if (buffer == null ) 
				buffer=channel.map(MapMode.READ_WRITE, position, length);
			else if(buffer.remaining()<length||!buffer.hasRemaining())
			{
				buffer.force();
				buffer=channel.map(MapMode.READ_WRITE, position, length);
			}
		} catch (IOException e) {
			logger.error("IOException",e);
			return null;
		}
		return buffer;
	}
	
	private void changeOtherFile()
	{
		stop();
		file=generateFile();
		try {
			randomAccessFile=new RandomAccessFile(file, "rw");
			channel=randomAccessFile.getChannel();
		} catch (FileNotFoundException e) {
			logger.error("不可能出错",e);
		}
		files.add(file);
	}
	
	private File generateFile()
	{
		String fileName=path+File.separator+System.currentTimeMillis()+"-"+Thread.currentThread().getId()+DiskTempStorage.FILE_SUFFIX;
		File file=new File(fileName);
		try {
			file.createNewFile();
			logger.debug("创建文件："+fileName);
		} catch (IOException e) {
			logger.error("生成记录文件失败"+fileName,e);
		}
		return file;
	}
	
	public void stop()
	{
		position=0;
		buffer=null;
		try {
			if(channel!=null)
				channel.close();
			if(randomAccessFile!=null)
				randomAccessFile.close();
		} catch (IOException e1) {
			logger.error(file+"文件关闭出错",e1);
		}
	}

	public List<File> getFiles() {
		return files;
	}
}
